This page has been superceded by a wiki version of this example: CreateLinkUsingCom


/* 

IShellLink Example for D

File:      createLink.d
Author:    Justin C Calvarese
Website:   http://jcc_7.tripod.com/d/
License:   Public Domain


- Ported to DMD D version 0.59 from BCX/LCC-Win32 by J C Calvarese
- Based on "BCX COM EXAMPLE" (by dl_programmer) 
- BCX source in makelink.zip at http://groups.yahoo.com/group/BCX/files/Source_Code/
- Creates a Windows shortcut to an executable, adding several properties.


Compile like this...
dmd createLink ole32.lib uuid.lib


Link with:   

ole32.lib    
---------
_CoUninitialize@0
_CoInitialize@4
_CoCreateInstance@20

uuid.lib
--------
_CLSID_ShellLink

*/

import std.c.windows.windows;
import std.string;
import std.c.windows.com;



/* Windows API constants */

const int SW_SHOW =5;
const int CP_ACP = 0;  //  default to ANSI code page


extern(C) const GUID CLSID_ShellLink     = {0x00021401, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]};
extern(C) const IID IID_IShellLinkA      = {0x000214EE, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]};
extern(C) const IID IID_IPersistFile     = {0x0000010B, 0x0000, 0x0000, [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46]};
alias IID_IShellLinkA IID_IShellLink;



/* Windows API types */

alias ushort *LPWSTR;

struct SHITEMID {
    USHORT cb;
    BYTE abID[1];
} 
alias SHITEMID* LPSHITEMID;

struct ITEMIDLIST {
    SHITEMID mkid;
}
alias ITEMIDLIST* LPCITEMIDLIST;
alias ITEMIDLIST* LPITEMIDLIST;


struct WIN32_FIND_DATA 
{
    DWORD dwFileAttributes;
    FILETIME ftCreationTime;
    FILETIME ftLastAccessTime;
    FILETIME ftLastWriteTime;
    DWORD nFileSizeHigh;
    DWORD nFileSizeLow;
    DWORD dwReserved0;
    DWORD dwReserved1;
    char cFileName[MAX_PATH];
    char cAlternateFileName[14];
    WORD dummy;
} 
alias WIN32_FIND_DATA* LPWIN32_FIND_DATA, PWIN32_FIND_DATA;

struct WIN32_FIND_DATAA 
{
    DWORD dwFileAttributes;
    FILETIME ftCreationTime;
    FILETIME ftLastAccessTime;
    FILETIME ftLastWriteTime;
    DWORD nFileSizeHigh;
    DWORD nFileSizeLow;
    DWORD dwReserved0;
    DWORD dwReserved1;
    CHAR cFileName[MAX_PATH];
    CHAR cAlternateFileName[14];
    WORD dummy;
}
alias WIN32_FIND_DATAA* LPWIN32_FIND_DATAA, PWIN32_FIND_DATAA;

struct WIN32_FIND_DATAW 
{
        DWORD dwFileAttributes;
        FILETIME ftCreationTime;
        FILETIME ftLastAccessTime;
        FILETIME ftLastWriteTime;
        DWORD nFileSizeHigh;
        DWORD nFileSizeLow;
        DWORD dwReserved0;
        DWORD dwReserved1;
        WCHAR cFileName[MAX_PATH];
        WCHAR cAlternateFileName[14];
        WORD dummy;
}
alias WIN32_FIND_DATAW* LPWIN32_FIND_DATAW, PWIN32_FIND_DATAW;



/* Windows API functions */


extern(Windows) int MultiByteToWideChar(UINT, DWORD, LPCSTR, int, LPWSTR, int);

alias MessageBoxA MessageBox;



/* objidl.h excerpt */

extern(C) /+const+/ extern IID /+IID_IPersistFile+/ IID_IPERSISTFILE;

extern(Windows) interface IPersistFile: IUnknown
{
/+    HRESULT (_stdcall *QueryInterface)(IPersistFile*,REFIID,void **);
    ULONG (_stdcall *AddRef)(IPersistFile*);
    ULONG (_stdcall *Release)(IPersistFile*);+/
    HRESULT GetClassID(CLSID*);
    HRESULT IsDirty();
    HRESULT Load(LPCOLESTR, DWORD);
    HRESULT Save(LPCOLESTR, BOOL);
    HRESULT SaveCompleted(LPCOLESTR);
    HRESULT GetCurFile(LPOLESTR*);
}

/* end of objidl.h excerpt */



/* shobjidl.h excerpt */

extern(Windows) interface IPersistIDList: IUnknown
{
/+   HRESULT QueryInterface(REFIID, void **);
   ULONG AddRef();
   ULONG Release();+/
   HRESULT GetClassID(CLSID*);
   HRESULT SetIDList(LPCITEMIDLIST);
   HRESULT GetIDList(LPITEMIDLIST*);
}

extern(Windows) interface IShellLink: IUnknown
{
/+   HRESULT QueryInterface(REFIID, void **);
   ULONG AddRef();
   ULONG Release();+/
   HRESULT GetPath(LPSTR, int, WIN32_FIND_DATAA*, DWORD);
   HRESULT GetIDList(LPITEMIDLIST*);
   HRESULT SetIDList(LPCITEMIDLIST);
   HRESULT GetDescription(LPSTR, int);
   HRESULT SetDescription(LPCSTR);
   HRESULT GetWorkingDirectory(LPSTR, int);
   HRESULT SetWorkingDirectory(LPCSTR);
   HRESULT GetArguments(LPSTR, int);
   HRESULT SetArguments(LPCSTR);
   HRESULT GetHotkey(WORD*);
   HRESULT SetHotkey(WORD);
   HRESULT GetShowCmd(int*);
   HRESULT SetShowCmd(int);
   HRESULT GetIconLocation(LPSTR, int, int*);
   HRESULT SetIconLocation(LPCSTR, int);
   HRESULT SetRelativePath(LPCSTR, DWORD);
   HRESULT Resolve(HWND, DWORD);
   HRESULT SetPath(LPCSTR);
}

/* end of shobjidl.h excerpt */



void main()
{

    /* You'll probably need to change some paths to reflect your system. */
    
    char[] SCPath = "c:\\windows\\";
    char[] szFile;
    char[] szTarget;
    char[] szDesc;
    char[] szIcon;
 

    szFile   = SCPath ~ "explorer.exe";
    szTarget = SCPath ~ "d_shortcut.lnk";

    szIcon = "c:\\dmd\\src\\jcc_7\\examples\\various\\fldr_a.ico";
    szDesc = "Shortcut to test.lnk using D!";

    if (CreateLink(szFile, szTarget, szDesc, szIcon) == S_OK)
        MessageBox(null, "Your shortcut has been created!",  "Look at that, D does do COM!", 0);
    else
        MessageBox(null, "An error occured while trying to create your shortcut", "Aw man...", 0); 
}



/* Helpful functions */

char[] Left(char[] s, int leng)
{
    /* Left$(s$, leng) */
    if (leng <= s.length) return s[0..leng];
    return s[];
} 


char[] AppPath(char[] path)
{
  /* --------------------------------------------------------------------------
     DESCRIPTION: Gets a path from full path name
           INPUT: String to full path name
          OUTPUT: String to path name
           USAGE: buffer$ = AppPath$("c:\your directory\your file.exe")
         RETURNS: c:\your directory\
     -------------------------------------------------------------------------- */
    return Left(path, find(path, cast(char[]) "\\"));
}


HRESULT CreateLink(char[] lpszPathObj, char[] lpszPathLink,  char[] lpszDesc, char[] lpszIcon)
{
   /* --------------------------------------------------------------------------
      DESCRIPTION: Creates a Windows shortcut
            INPUT: string to EXE, string to shortcut, string to description,
                   string to icon
           OUTPUT: HRESULT to success or failure
            USAGE: result = CreateLink("c:\in.exe", "c:\out.lnk, "description")
          RETURNS: S_OK if the interface is supported, E_NOINTERFACE if not.
      -------------------------------------------------------------------------- */
    
    HRESULT hres;
    IShellLink psl;

    CoInitialize(null);     /* Initialize the COM object */

    /* Get a pointer to the IShellLink interface. */
    hres = CoCreateInstance(&CLSID_ShellLink, null, CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl);

    if (SUCCEEDED(hres)) 
    {
        IPersistFile ppf;

        /* Sets shortcut location */
        psl.SetPath(cast(char*) (lpszPathObj ~ \0));

        /* Sets shortcut description */
        psl.SetDescription(cast(char*) (lpszDesc ~ \0));

        /* Gives shortcut an icon */
        psl.SetIconLocation(cast(char*) (lpszIcon ~ \0), 0);

        /* Make it full screen */
        psl.SetShowCmd(SW_SHOW); /* MAXIMIZED */

        /* Set default path */
        psl.SetWorkingDirectory(cast(char*) (AppPath(lpszPathObj) ~ \0));

/+      /* Set arguments */
        psl.SetArguments("-arg1 -arg2 -arg3"); /*UNCOMMENT THIS IF YOU WANT TO SET ARGUMENTS*/

        /* **** Other properties are available! ****
           Do not uncomment unless you define the other parameters.
           Read the Microsoft PSDK for more info.                   */
        psl.SetHotkey(wHotkey);
        psl.SetIDList(pidl);
        psl.SetRelativePath(pszPathRel, null); +/

        /* Query IShellLink for the IPersistFile interface for saving the 
           shortcut in persistent storage. */
        hres = psl.QueryInterface(&IID_IPersistFile, cast(void **) &ppf);

        if (SUCCEEDED(hres))
        { 
            WORD wsz[MAX_PATH];
 
            /* Ensure that the string is ANSI. */
            MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
 
            /* Save the link by calling IPersistFile::Save. */
            hres = ppf.Save(cast(wchar*) wsz, cast(int) true);
            ppf.Release();
        }
        psl.Release();
    }

    CoUninitialize(); /* Uninitialize the COM object */
    return hres;
}